package com.example.educationblockchain.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.educationblockchain.mapper.BlockMapper;
import com.example.educationblockchain.mapper.StudentLoginMapper;
import com.example.educationblockchain.model.*;
import com.example.educationblockchain.util.Encrypted;
import org.apache.shiro.SecurityUtils;
import org.java_websocket.WebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class StudentInformationService {
    @Autowired
    BlockMapper blockMapper;

    @Autowired
    DataBlockService dataBlockService;

    @Autowired
    P2PService p2PService;

    @Autowired
    StudentLoginMapper studentLoginMapper;

    Encrypted encrypted = new Encrypted();

    public Map<String,Object> getData() throws BadPaddingException, NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, UnsupportedEncodingException, NoSuchProviderException, InvalidKeyException, InvalidKeySpecException {
        Map<String,Object> result = new HashMap<>();

        List<String> ws = new ArrayList<>();

        for (WebSocket socket : p2PService.getSockets()) {
            ws.add(socket.getRemoteSocketAddress().toString());
        }

        Block block = new Block();


        Map map = (Map) SecurityUtils.getSubject().getPrincipal();

        String number = map.get("id").toString();

        List<Block> blockList= blockMapper.selectBlocksOrder(number);
        block = blockList.get(blockList.size()-1);

        List<DataBlock> dataBlocks = dataBlockService.findDataBlockByHash(block.getHash());

        System.out.println(dataBlocks.get(0));

        System.out.println(block);

        Data data = new Data();

        try {
            data = encrypted.Decrypt(block,dataBlocks.get(0).getDataBlock());
            System.out.println(data);
            result.put("error","false");
        } catch (Exception e) {
            System.out.println("粗错了");
            result.put("error","true");
        }

        result.put("data",data);

        result.put("hash",block.getHash());

        result.put("maxPage",blockList.size());

        result.put("index",block.getIndex());

        result.put("ws",ws);

        return result;
    }

    public Map<String,Object> getDataByPage(int page) throws BadPaddingException, NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, UnsupportedEncodingException, NoSuchProviderException, InvalidKeyException, InvalidKeySpecException {
        Map<String,Object> result = new HashMap<>();

        Block block = new Block();


        Map map = (Map) SecurityUtils.getSubject().getPrincipal();

        String number = map.get("id").toString();

        List<Block> blockList= blockMapper.selectBlocksOrder(number);
        block = blockList.get(page-1);

        List<DataBlock> dataBlocks = dataBlockService.findDataBlockByHash(block.getHash());

        System.out.println(dataBlocks.get(0));

        System.out.println(block);

        Data data = encrypted.Decrypt(block,dataBlocks.get(0).getDataBlock());

        result.put("data",data);

        result.put("hash",block.getHash());

        result.put("maxPage",blockList.size());

        result.put("index",block.getIndex());

        return result;
    }

    public void changeStudentInfo(Map<String,Object> map) throws BadPaddingException, NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, UnsupportedEncodingException, NoSuchProviderException, InvalidKeyException, InvalidKeySpecException {
        String hash = map.get("hash").toString();

        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("_hash",hash);

        Block block = blockMapper.selectOne(wrapper);

        List<DataBlock> dataBlocks = dataBlockService.findDataBlockByHash(block.getHash());

        System.out.println(dataBlocks.get(0));

        System.out.println(block);

        Data data = encrypted.Decrypt(block,dataBlocks.get(0).getDataBlock());

        data.setPlace(map.get("place").toString());
        data.setPostCode(map.get("postCode").toString());
        data.setPhone(map.get("phone").toString());
        data.setMail(map.get("mail").toString());

        Map<String,String> en = encrypted.Encrypt(data);
        System.out.println(en);

        Block b = new Block();

        if(data.get_class()!=null){
            b.set_class(data.get_class());
        }
        if(data.getName()!=null){
            b.setName(data.getName());
        }
        if(data.getNumber()!=null){
            b.setNumber(data.getNumber());
        }
        b.setTimestamp(System.currentTimeMillis());
        b.setC4(en.get("c4"));
        b.setPk(en.get("pk"));
        b.setSk(en.get("sk"));

        long index = blockMapper.selectBlockNum();

        b.setIndex(index);

        QueryWrapper w = new QueryWrapper();
        w.eq("_index",index-1);

        b.setPreviousHash(blockMapper.selectOne(w).getHash());

        b.setHash(calculateHash(b));

        blockMapper.insert(b);

        DataBlock dataBlock = new DataBlock(b.getHash(),en.get("c5"));

        dataBlockService.saveDataBlock(dataBlock);

        p2PService.responseNewBlockMsg(b, dataBlock);

        System.out.println(dataBlock);
        System.out.println(b);

    }

    public String changePassword(Map<String,String> map){
        String orginPwd = map.get("orginPwd");
        String newPwd = map.get("newPwd");

        Map adminData = (Map) SecurityUtils.getSubject().getPrincipal();
        String id = adminData.get("id").toString();

        StudentLogin studentLogin = studentLoginMapper.selectById(id);
        if(!studentLogin.getPassword().equals(orginPwd)){
            return "pwd error";
        }else {
            studentLogin.setPassword(newPwd);

            QueryWrapper wrapper = new QueryWrapper();
            wrapper.eq("id", id);
            studentLoginMapper.update(studentLogin,wrapper);
            return "success";
        }
    }


    public String calculateHash(Block block){
        return encrypted.SHA256(block.getIndex()+block.getPreviousHash()+block.getTimestamp()+block.getName()
                +block.getClass()+block.getNumber()+block.getC4()+block.getPk()+block.getSk());
    }
}
